package org.dna;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;

import org.apache.felix.framework.FrameworkFactory;
import org.apache.log4j.Logger;
import org.apache.wicket.Application;
import org.apache.wicket.Component;
import org.apache.wicket.Page;
import org.apache.wicket.Request;
import org.apache.wicket.Response;
import org.apache.wicket.RestartResponseAtInterceptPageException;
import org.apache.wicket.Session;
import org.apache.wicket.authorization.Action;
import org.apache.wicket.authorization.IAuthorizationStrategy;
import org.apache.wicket.authorization.IUnauthorizedComponentInstantiationListener;
import org.apache.wicket.protocol.http.WebApplication;
import org.dna.metronomo.persistence.IActivityDAO;
import org.dna.metronomo.persistence.IJobDAO;
import org.dna.metronomo.persistence.IUserDAO;
import org.dna.wickwtui.LoginPage;
import org.dna.wickwtui.MetroPage;
import org.dna.wickwtui.activities.ManageActivityPage;
import org.osgi.framework.BundleException;
import org.osgi.framework.launch.Framework;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Application object for your web application. If you want to run this
 * application without deploying, run the Start class.
 * 
 * @see wicket.myproject.Start#main(String[])
 */
public class MetroApplication extends WebApplication {
	
	private static final Logger LOG = Logger.getLogger(MetroApplication.class);
	
	public static final class MetroAuthorizationStrategy implements
			IAuthorizationStrategy, IUnauthorizedComponentInstantiationListener {
		
		public boolean isActionAuthorized(Component component, Action action) {
			if (action.equals(Component.RENDER)) {
				Class<? extends Component> c = component.getClass();
				UserRoles userRoles = c.getAnnotation(UserRoles.class);
				if (userRoles != null) {
					User user = MetroSession.get().getUser();
					return (user != null && user.hasRole(userRoles.value()));
				}
			}
			return true;
		}

		public <T extends Component> boolean isInstantiationAuthorized(
				Class<T> componentClass) {
			if (MetroPage.class.isAssignableFrom(componentClass)) {
				return MetroSession.get().isAuthenticated();
			}
			return true;
		}

		public void onUnauthorizedInstantiation(Component component) {
			throw new RestartResponseAtInterceptPageException(LoginPage.class);
		}
	}

	private ApplicationContext m_context;
	
	private Framework m_fwk = null;

	/**
	 * Constructor
	 */
	public MetroApplication() {
		super();
	}

	public static MetroApplication get() {
		return (MetroApplication) Application.get();
	}

	/*
	 * Here init the Spring context
	 */
	@Override
	protected void init() {
		super.init();
		m_context = new ClassPathXmlApplicationContext("spring-context.xml");
		initSecurity();
		try {
			initFelix();
		} catch (Exception ex) {
			LOG.fatal("Cant' startup OSGi contained", ex);
		}
	}
	
	@Override
	protected void onDestroy() {
		shutdownFelix();
	}

	private void shutdownFelix() {
		try {
			m_fwk.stop();
		} catch (BundleException ex) {
			LOG.fatal("Cant' stop OSGi contained", ex);
		}
	}

	@Override
	public Class<? extends Page> getHomePage() {
		return ManageActivityPage.class;
	}

	public IActivityDAO getActivityDAO() {
		return (IActivityDAO) m_context.getBean("activityDAO");
	}

	public IJobDAO getJobDAO() {
		return (IJobDAO) m_context.getBean("jobDAO");
	}

	public IUserDAO getUserDAO() {
		return (IUserDAO) m_context.getBean("userDAO");
	}

	@Override
	public Session newSession(Request request, Response response) {
		return new MetroSession(request);
	}

	private void initSecurity() {
		MetroAuthorizationStrategy tmp = new MetroAuthorizationStrategy();
		getSecuritySettings().setAuthorizationStrategy(tmp);
		getSecuritySettings()
				.setUnauthorizedComponentInstantiationListener(tmp);
	}
	
	private void initFelix() throws Exception {
		m_fwk = getFrameworkFactory().newFramework(null);
        m_fwk.init();
//        AutoProcessor.process(null, m_fwk.getBundleContext());
        m_fwk.start();
	}

	private FrameworkFactory getFrameworkFactory() throws Exception {
		URL url = this.getClass().getClassLoader().getResource(
				"META-INF/services/org.osgi.framework.launch.FrameworkFactory");
		if (url != null) {
			BufferedReader br = new BufferedReader(new InputStreamReader(url
					.openStream()));
			try {
				for (String s = br.readLine(); s != null; s = br.readLine()) {
					s = s.trim();
					// Try to load first non-empty, non-commented line.
					if ((s.length() > 0) && (s.charAt(0) != '#')) {
						return (FrameworkFactory) Class.forName(s)
								.newInstance();
					}
				}
			} finally {
				if (br != null)
					br.close();
			}
		}
		throw new Exception("Could not find framework factory.");
	}
}
